package download.itydl.com.sinlethread.mutilthread.services;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import download.itydl.com.sinlethread.mutilthread.bean.FileInfo;
import download.itydl.com.sinlethread.mutilthread.bean.ThreadInfo;
import download.itydl.com.sinlethread.mutilthread.db.ThreadDao;
import download.itydl.com.sinlethread.mutilthread.db.ThreadDaoImpl;

public class DownLoadTask {

    private static final String TAG = "DownloadService2";
    private Context mContext;
    private FileInfo mFileInfo;
    private int runThreadCount = 1;
    private ThreadDao mDao;
    /**
     * 线程信息集合，方便管理线程
     */
    private List<DownThread> downThreads = new ArrayList<>();
    public boolean isPause = false;
    /**
     * 记录文件下载总进度
     */
    private long finish;

    public DownLoadTask(Context context, FileInfo mFileInfo, int runThreadCount) {
        this.mContext = context;
        this.mFileInfo = mFileInfo;
        this.runThreadCount = runThreadCount;
        mDao = new ThreadDaoImpl(mContext);
    }

    /**
     * 开始下载
     */
    public void downLoad() {
        List<ThreadInfo> threadInfos = mDao.getThreadInfo(mFileInfo.getUrl());
        if (threadInfos.size() == 0) {
            // 数据库第一次创建线程信息，封装线程信息Bean
            long length = mFileInfo.getLength() / runThreadCount;
            for (int i = 0; i < runThreadCount; i++) {
                long start = i * length;
                long end = (i + 1) * length - 1;
                if (i + 1 == runThreadCount) {
                    end = mFileInfo.getLength();
                }
                ThreadInfo threadInfo = new ThreadInfo(i, mFileInfo.getUrl(), start, end, 0);
                threadInfos.add(threadInfo);
                // 数据库还没有线程信息，在第一次创建的时候把表也创建了
                mDao.insertThreadInfo(threadInfo);
            }
        }
        for (ThreadInfo threadInfo : threadInfos) {
            // 有多少线程信息，就对应开启多少个线程；因为一个线程信息对应一个线程
            DownThread downThread = new DownThread(threadInfo);
            downThread.start();
            // 方便对后期的线程进行管理
            downThreads.add(downThread);
        }
    }

    class DownThread extends Thread {

        private ThreadInfo mThreadInfo;
        /**
         * 用于标记当前线程是否下载完毕
         */
        private boolean isFinish;

        public DownThread(ThreadInfo threadInfo) {
            this.mThreadInfo = threadInfo;
        }

        @Override
        public void run() {
            HttpURLConnection conn = null;
            InputStream inputStream = null;
            RandomAccessFile raf = null;
            try {
                // 链接文件地址
                URL url = new URL(mFileInfo.getUrl());
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(3000);
                conn.setRequestMethod("GET");

                // 设置服务器请求区间
                // 起始值 + 数据库表中已经存储的进度 为请求的新的区间开始位置(注：第一次mThreadInfo.getFinished()=0，下载后就不为0，所以后面要保存这个进度)
                // 数据库表中已经存储的进度
                long finished = mThreadInfo.getFinished();
                long start = mThreadInfo.getStart() + finished;
                long end = mThreadInfo.getEnd();
                conn.setRequestProperty("Range", "bytes=" + start + "-" + end);

                // 设置文件下载位置,保证每个线程下载的时候是从指定位置下载
                File file = new File(DownloadService.DOWNLOAD_PATH, mFileInfo.getFileName());
                raf = new RandomAccessFile(file, "rwd");
                raf.seek(start);

                Intent intent = new Intent(DownloadService.ACTION_UPDATE);

                // 注意是文件信息
                finish += mThreadInfo.getFinished();
                Log.e(TAG, "finish======:" + finish);

                // 把数据写入文件，同时暂停时保存到数据库
                if (conn.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
                    // 部分数据请求，结果是206
                    inputStream = conn.getInputStream();
                    byte[] bytes = new byte[4 * 1024];
                    int len = -1;
                    // 把数据写入文件，同时暂停时保存到数据库
                    long startTime = System.currentTimeMillis();
                    while ((len = inputStream.read(bytes)) != -1) {
                        // 暂停的话不再往下写入
                        if (isPause) {
                            // 暂停时保存到数据库
                            mDao.upDateThreadInfo(mFileInfo.getUrl(), mThreadInfo.getThreadId(), mThreadInfo.getFinished());
                            return;
                        }
                        raf.write(bytes, 0, len);
                        // 累加总进度
                        finish += len;
                        // 设置最新进度 : 上一次进度 + len
                        mThreadInfo.setFinished(len + mThreadInfo.getFinished());
                        // 每隔1s发送一次广播，把进度往外推
                        if (System.currentTimeMillis() - startTime > 1000) {
                            startTime = System.currentTimeMillis();
                            // 发送广播
                            Log.e(TAG, "finish * 100 / mFileInfo.getLength():~~~~" + finish * 100 + "/" + mFileInfo.getLength());
                            long progress = finish * 100 / mFileInfo.getLength();

                            Log.e(TAG, "progress:" + progress);

                            // 发送当前文件的id，告知Activity当前应该更新哪个item
                            intent.putExtra("id", mFileInfo.getId());
                            intent.putExtra("finished", progress);
                            mContext.sendBroadcast(intent);
                        }
                    }
                }

                isFinish = true;
                // 当前文件全部下载结束的时候，删除数据库下载信息（按照url删除）
                checkAllDownloadThread();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (conn != null && inputStream != null && raf != null) {
                        conn.disconnect();
                        inputStream.close();
                        raf.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void checkAllDownloadThread() {
        boolean allFinished = true;
        for (DownThread downThread : downThreads) {
            if (!downThread.isFinish) {
                allFinished = false;
                break;
            }
        }
        if (allFinished) {
            // 删除数据库信息
            mDao.deleteThreadInfo(mFileInfo.getUrl());
            // 表示全部都下载完毕,发送一个全部下载完毕的广播，让UI层进度为0
            Intent intent = new Intent(DownloadService.ACTION_FINISHED);
            intent.putExtra("fileinfo", mFileInfo);
            mContext.sendBroadcast(intent);

        }
    }

}
